package elasticTool

//es操作文档
//https://www.tizi365.com/archives/850.html
//https://zhuanlan.zhihu.com/p/347419756
import (
	"context"
	"fmt"
	elastic "github.com/olivere/elastic/v7"
	"github.com/pkg/errors"
	"io"
	"strconv"
)
type Es struct {
	Client *elastic.Client
	Index string
}

func NewClient(url []string, user, password string) (*elastic.Client, error) {
	sniffOpt := elastic.SetSniff(false)
	var client *elastic.Client
	var err error
	if len(user) > 0 && len(password) > 0{
		auth := elastic.SetBasicAuth(user, password)
		client, err = elastic.NewClient(elastic.SetURL(url...), sniffOpt, auth)
	}else{
		client, err = elastic.NewClient(elastic.SetURL(url...), sniffOpt)
	}
	return client, err
}

func NewEs(client *elastic.Client, index string) *Es {
	return &Es{
		Client: client,
		Index: index,
	}
}

func (e *Es) Create(data interface{}) error  {
	indexResult, err := e.Client.Index().
		Index(e.Index).
		//Id("1").
		BodyJson(data).
		Do(context.TODO())
	if err != nil {
		return err
	}
	if indexResult == nil {
		return errors.New("没有影响数据")
	}
	return nil
}

//删除
func (e *Es) DeleteForEsId(id string) error {
	_, err := e.Client.Delete().Index(e.Index).
		Id(id).
		Do(context.Background())
	if err != nil {
		return err
	}
	return nil
	//fmt.Printf("delete result %s\n", res.Result)
}

//根据条件删除，这里的默认条件是mysql的id
func (e *Es) Delete(id int64) error {
	_, err := e.Client.DeleteByQuery(e.Index). // 设置索引名
		// 设置查询条件为: Author = tizi
		Query(elastic.NewTermQuery("id", strconv.FormatInt(id, 10))).
		// 文档冲突也继续删除
		ProceedOnVersionConflict().
		Do(context.Background())

	if err != nil {
		return err
	}
	return nil
}

//修改
func (e *Es) Update(id string, data interface{}) error {
	_, err := e.Client.Update().
		Index(e.Index).
		Id(id).
		Doc(data).
		Do(context.Background())
	if err != nil {
		return err
	}
	return nil
	//fmt.Printf("update age %s\n", res.Result)

}

//查找
func (e *Es) GetFromId(id string) ([]byte, error) {
	//通过id查找
	get1, err := e.Client.Get().Index(e.Index).Id(id).Do(context.Background())
	if err != nil {
		return nil, err
	}
	if !get1.Found {
		return nil, errors.New("记录不存在")
		//fmt.Printf("Got document %s in version %d from index %s, type %s\n", get1.Id, get1.Version, get1.Index, get1.Type)
	}
	// 提取文档内容，原始类型是json数据
	data, _ := get1.Source.MarshalJSON()
	return data, nil
}

//按mysql的id查询一条信息
func (e *Es) GetOne(id int64, obj interface{}) ([]byte, string, error) {
	// 创建term查询条件，用于精确查询
	termQuery := elastic.NewTermQuery("id", strconv.FormatInt(id, 10))

	searchResult, err := e.Client.Search().
		Index(e.Index).   // 设置索引名
		Query(termQuery).   // 设置查询条件
		From(0). // 设置分页参数 - 起始偏移量，从第0行记录开始
		Size(1).   // 设置分页参数 - 每页大小
		Pretty(true).       // 查询结果返回可读性较好的JSON格式
		Do(context.Background())             // 执行请求

	if err != nil {
		return nil, "", err
	}

	if searchResult.TotalHits() > 0 {
		for _, val := range searchResult.Hits.Hits {
			return val.Source, val.Id, nil
		}
		// 查询结果不为空，则遍历结果
		// 通过Each方法，将es结果的json结构转换成struct对象
		/*for key, item := range searchResult.Each(reflect.TypeOf(obj)) {
			return item, searchResult.Hits.Hits[key].Id, nil
		}*/
	}
	return nil, "",errors.New("记录不存在")
}

//深度搜索，游标
func (e *Es) Search(query elastic.Query, size int, scrollId string, sortKey string, sortValue string) ([]string, string, error) {
	var res *elastic.SearchResult
	var err error
	if scrollId == ""{
		ascending := true
		if(sortValue == "desc"){
			ascending = false
		}
		res, err = e.Client.Scroll().Index(e.Index).
			Query(query).
			Sort(sortKey, ascending).
			Scroll("5m").
			Size(size).
			Do(context.Background())
	}else{
		res, err = e.Client.Scroll("1m").ScrollId(scrollId).Do(context.TODO())
	}

	if err != nil{
		if errors.Is(err, io.EOF){
			return nil, "",nil
		}
		return nil, "", errors.Wrap(err, "查询时出错")
	}
	if res.TotalHits() > 0 {
		//fmt.Println(res.ScrollId)
		list := make([]string, 0)
		for _, val := range res.Hits.Hits {
			source := string(val.Source)
			fmt.Println(source)
			if source != ""{
				list = append(list, string(val.Source))
			}
		}
		if len(list) == 0{
			return nil, "", err
		}
		return list, res.ScrollId, nil
	}
	return nil, "",nil
}

//搜索
/*func query() {
	var res *elastic.SearchResult
	var err error
	//取所有
	res, err = client.Search("megacorp").Type("employee").Do(context.Background())
	printEmployee(res, err)

	//字段相等
	q := elastic.NewQueryStringQuery("last_name:Smith")
	res, err = client.Search("megacorp").Type("employee").Query(q).Do(context.Background())
	if err != nil {
		println(err.Error())
	}
	printEmployee(res, err)

	//条件查询
	//年龄大于30岁的
	boolQ := elastic.NewBoolQuery()
	boolQ.Must(elastic.NewMatchQuery("last_name", "smith"))
	boolQ.Filter(elastic.NewRangeQuery("age").Gt(30))
	res, err = client.Search("megacorp").Type("employee").Query(q).Do(context.Background())
	printEmployee(res, err)

	//短语搜索 搜索about字段中有 rock climbing
	matchPhraseQuery := elastic.NewMatchPhraseQuery("about", "rock climbing")
	res, err = client.Search("megacorp").Type("employee").Query(matchPhraseQuery).Do(context.Background())
	printEmployee(res, err)

	//分析 interests
	aggs := elastic.NewTermsAggregation().Field("interests")
	res, err = client.Search("megacorp").Type("employee").Aggregation("all_interests", aggs).Do(context.Background())
	printEmployee(res, err)

}*/
